﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using Server;

namespace Client
{
    public partial class Form1 : Form
    {
        public delegate void UpdateRichEditCallback(string text, Color color);
        IAsyncResult m_result;
        public AsyncCallback m_pfnCallBack;
        public Socket m_clientSocket;

        public Form1()
        {
            InitializeComponent();
            textBoxIP.Text = GetIP();
            bxinput.KeyPress += new KeyPressEventHandler(bxinput_KeyPress);
            this.InputLanguageChanged += new InputLanguageChangedEventHandler(Form1_InputLanguageChanged);
            this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);

            RTB0.BackColor = Properties.Settings.Default.BGcolor;
            RTB0.Font = Properties.Settings.Default.RTBfont;
        }

        void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.BGcolor = RTB0.BackColor;
            Properties.Settings.Default.RTBfont = RTB0.Font;
            Properties.Settings.Default.Save();
        }

        void Form1_InputLanguageChanged(object sender, InputLanguageChangedEventArgs e)
        {
            if (e.InputLanguage.Culture.TwoLetterISOLanguageName.Equals("ja"))
            {
                RTB0.ImeMode = System.Windows.Forms.ImeMode.Katakana;
            }
        }

        void bxinput_KeyPress(object sender, KeyPressEventArgs e)
        {
            if ((Keys)e.KeyChar == Keys.Enter && !string.IsNullOrEmpty(bxinput.Text) && m_clientSocket != null)
            {
                string buffer;
                if (bxinput.Text.StartsWith("/"))
                {
                    buffer = bxinput.Text;
                    bxinput.Clear();
                    e.Handled = true;
                }
                else
                {
                    //append chat mode
                    buffer = string.Format("{0} {1}", GetChatMode(), bxinput.Text);
                    bxinput.Clear();
                    e.Handled = true;
                }

                try
                {
                    Server.SocketPacket snd = new Server.SocketPacket(m_clientSocket, 0);
                    snd.message = buffer;
                    m_clientSocket.Send(snd.Serialize());
                }
                catch (SocketException se)
                {
                    MessageBox.Show(se.Message);
                }
            }
        }


        string GetChatMode()
        {
            switch (ModeComboBox.Text)
            {
                case "Say":
                    return "/s";
                case "Tell":
                    return "/t";
                case "Shout":
                    return "/sh";
                case "Party":
                    return "/p";
                case "Linkshell":
                    return "/l";
                default:
                    return "/s";
            }
        }

        void buttonConnect_Click(object sender, System.EventArgs e)
        {
            if (textBoxIP.Text == "" || textBoxPort.Text == "")
            {
                MessageBox.Show("IP Address and Port Number are required to connect to the Server\n");
                return;
            }
            try
            {
                UpdateControls(false);
                m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPAddress ip = IPAddress.Parse(textBoxIP.Text);
                int iPortNo = System.Convert.ToInt16(textBoxPort.Text);
                IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
                m_clientSocket.Connect(ipEnd);
                if (m_clientSocket.Connected)
                {
                    UpdateControls(true);
                    WaitForData();
                }
            }
            catch (SocketException se)
            {
                string str;
                str = "\nConnection failed, is the server running?\n" + se.Message;
                MessageBox.Show(str);
                UpdateControls(false);
            }
        }

        public void WaitForData()
        {
            try
            {
                if (m_pfnCallBack == null)
                {
                    m_pfnCallBack = new AsyncCallback(OnDataReceived);
                }
                Server.SocketPacket theSocPkt = new Server.SocketPacket(m_clientSocket, 0);
                m_result = m_clientSocket.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length,SocketFlags.None,m_pfnCallBack,theSocPkt);
            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
            }

        }
        public void OnDataReceived(IAsyncResult asyn)
        {
            try
            {
                SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
                int iRx = theSockId.m_currentSocket.EndReceive(asyn);
                for (int i = 0; i < iRx; i++)
                {
                    theSockId.TransmissionBuffer.Add(theSockId.dataBuffer[i]);
                }
                SocketPacket rcv = theSockId.DeSerialize();
                AppendToRichEditControl(rcv.message,rcv.color);
                WaitForData();
            }
            catch (ObjectDisposedException)
            {
                System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
            }
        }
        private void UpdateControls(bool connected)
        {
            buttonConnect.Enabled = !connected;
            buttonDisconnect.Enabled = connected;
            string connectStatus = connected ? "Connected" : "Not Connected";
            this.Text = Application.ProductName + ": " + connectStatus;
        }

        void buttonDisconnect_Click(object sender, System.EventArgs e)
        {
            if (m_clientSocket != null)
            {
                m_clientSocket.Close();
                m_clientSocket = null;
                UpdateControls(false);
            }
        }

        public void AppendToRichEditControl(string msg, Color color)
        {
            if (InvokeRequired)
            {
                object[] pList = { msg, color };
                RTB0.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList);
            }
            else
            {
                OnUpdateRichEdit(msg, color);
            }
        }
        private void OnUpdateRichEdit(string msg, Color color)
        {
            RTB0.SelectionColor = color;
            RTB0.AppendText(msg + "\n");
            RTB0.ScrollToCaret();
        }

        String GetIP()
        {
            String strHostName = Dns.GetHostName();
            IPHostEntry iphostentry = Dns.GetHostByName(strHostName);
            String IPStr = "";
            foreach (IPAddress ipaddress in iphostentry.AddressList)
            {
                IPStr = ipaddress.ToString();
                return IPStr;
            }
            return IPStr;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            colorDialog1.Color = RTB0.BackColor;
            if (colorDialog1.ShowDialog() == DialogResult.OK)
                RTB0.BackColor = colorDialog1.Color;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            fontDialog1.Font = RTB0.Font;
            if (fontDialog1.ShowDialog() == DialogResult.OK)
                RTB0.Font = fontDialog1.Font;
        }

    }
}
